package net.akabana.blazeds.endpoint;

import java.util.List;

import flex.messaging.FlexContext;
import flex.messaging.FlexSession;
import flex.messaging.HttpFlexSession;
import flex.messaging.client.FlexClient;
import flex.messaging.endpoints.DuplicateSessionException;

public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {

    private static final int ERR_MSG_DUPLICATE_SESSIONS_DETECTED = 10035;
    
    private static final String REQUEST_ATTR_DUPLICATE_SESSION_FLAG = "flex.messaging.request.DuplicateSessionDetected";

    @Override
    public FlexClient setupFlexClient(String id) {
        FlexClient flexClient = null;
        if (id == null) {
            log.error("id is null");
        } else {
            if (id.equals(FlexClient.NULL_FLEXCLIENT_ID)) {
                log.debug("id is " + FlexClient.NULL_FLEXCLIENT_ID);
                id = null;
            }
            flexClient = getMessageBroker().getFlexClientManager().getFlexClient(id);

            final FlexSession currentSession = FlexContext.getFlexSession();
            final List<FlexSession> oldSessions = flexClient.getFlexSessions();
            int n = oldSessions.size();
            log.debug("oldSessions size is " + n);
            if (n > 0) {
                int count = 0;
                FlexSession oldSession;
                for (int i = 0; i < n; i++) {
                    oldSession = oldSessions.get(i);
                    if (oldSession instanceof HttpFlexSession) {
                        count++;
                    }
                    if (count > 0) {
                        log.debug("oldSessions Id is " + oldSession.getId());
                        log.debug("curSession Id is " + currentSession.getId());
                        if (oldSession.getId().equals(currentSession.getId())) {
                            //reuse FlexClient and FlexSession
                        } else {
                            log.error("throw DuplicateSessionException");
                            DuplicateSessionException e = new DuplicateSessionException();
                            e.setMessage(ERR_MSG_DUPLICATE_SESSIONS_DETECTED);
                            throw e;
                        }
                        break;
                    }
                }
            } else {
                log.debug("registerFlexSession Id is " + currentSession.getId());
                flexClient.registerFlexSession(currentSession);
            }
            if( flexClient != null ){
                log.debug("flexClient Id is " + flexClient.getId());
                FlexContext.setThreadLocalFlexClient(flexClient);
            }
        }
        
        sessionDeplicationCheck(flexClient);

        return flexClient;
    }

    private void sessionDeplicationCheck(final FlexClient flexClient) {
        // Scan for duplicate HTTP-sessions and if found, invalidate them and throw a MessageException.
        // A request attribute is used to deal with batched AMF messages that arrive in a single request by trigger multiple passes through this method.
        boolean duplicateSessionDetected = (FlexContext.getHttpRequest().getAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG) != null);

        if (!duplicateSessionDetected)
        {
            List<FlexSession> sessions = flexClient.getFlexSessions();
            int n = sessions.size();
            if (n > 1)
            {
                int count = 0;
                for (int i = 0; i < n; i++)
                {
                    if (sessions.get(i) instanceof HttpFlexSession)
                        count++;
                    if (count > 1)
                    {
                        FlexContext.getHttpRequest().setAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG, Boolean.TRUE);
                        duplicateSessionDetected = true;
                        break;
                    }
                }
            }
        }

        // If more than one was found, remote host isn't using session cookies. Kill all duplicate sessions and return an error.
        // Simplest to just re-scan the list given that it will be very short, but use an iterator for concurrent modification.
        if (duplicateSessionDetected)
        {
            List<FlexSession> sessions = flexClient.getFlexSessions();
            for (FlexSession session : sessions)
            {
                if (session instanceof HttpFlexSession)
                {
                    session.invalidate();
                }
            }

            // Return an error to the client.
            DuplicateSessionException e = new DuplicateSessionException();
            e.setMessage(ERR_MSG_DUPLICATE_SESSIONS_DETECTED);
            throw e;
        }
    }
}